added Feb 2001 SDK
[windows-sources.git] / shared source / sscli20 / jscript / engine / constantwrapper.cs
blob12019568b2917c76709c6ad2e5b3001aa8e45686
1 // ==++==
2 //
3 //
4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
5 //
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
10 //
11 // You must not remove this notice, or any other, from this software.
12 //
13 //
14 // ==--==
16 /* This class is used to wrap up compile-time constants in AST nodes.
17 For the most part, this means enums, primitives, strings, types and name spaces.
18 However, it can also be used to wrap the builtin objects when in Fast mode.
19 Addditionally null (Empty.Value), DBNull.Value and Missing.Value can be wrapped.
21 No other kind of value should be wrapped by this class.
24 namespace Microsoft.JScript {
26 using System;
27 using System.Reflection;
28 using System.Reflection.Emit;
29 using System.Globalization;
31 internal class ConstantWrapper : AST{
32 internal Object value;
33 internal bool isNumericLiteral;
35 internal ConstantWrapper(Object value, Context context)
36 : base(context) {
37 if (value is ConcatString) value = value.ToString();
38 this.value = value;
39 this.isNumericLiteral = false;
42 internal override Object Evaluate(){
43 return this.value;
46 internal override IReflect InferType(JSField inference_target){
47 if (this.value == null || this.value is DBNull)
48 return Typeob.Object;
49 else if (this.value is ClassScope || this.value is TypedArray)
50 return Typeob.Type;
51 else if (this.value is EnumWrapper)
52 return ((EnumWrapper)this.value).classScopeOrType;
53 else
54 return Globals.TypeRefs.ToReferenceContext(this.value.GetType());
57 internal bool IsAssignableTo(Type rtype){
58 try{
59 Convert.CoerceT(this.value, rtype, false);
60 return true;
61 }catch{
62 return false;
66 internal override AST PartiallyEvaluate(){
67 return this;
70 public override String ToString(){
71 return this.value.ToString();
74 internal override void TranslateToIL(ILGenerator il, Type rtype){
75 if (rtype == Typeob.Void)
76 return;
77 Object val = this.value;
78 if (val is EnumWrapper && rtype != Typeob.Object && rtype != Typeob.String)
79 val = ((EnumWrapper)val).value;
80 if (this.isNumericLiteral && (rtype == Typeob.Decimal || rtype == Typeob.Int64 || rtype == Typeob.UInt64 || rtype == Typeob.Single))
81 val = this.context.GetCode();
82 if (!(rtype is TypeBuilder)){
83 try{
84 val = Convert.CoerceT(val, rtype);
85 }catch{
88 this.TranslateToIL(il, val, rtype);
91 private void TranslateToIL(ILGenerator il, Object val, Type rtype){
92 IConvertible ic = Convert.GetIConvertible(val);
93 switch (Convert.GetTypeCode(val, ic)){
94 case TypeCode.Empty:
95 il.Emit(OpCodes.Ldnull);
96 if (rtype.IsValueType)
97 Convert.Emit(this, il, Typeob.Object, rtype);
98 return;
99 case TypeCode.Object:
100 break;
101 case TypeCode.DBNull:
102 il.Emit(OpCodes.Ldsfld, Typeob.Null.GetField("Value"));
103 Convert.Emit(this, il, Typeob.Null, rtype);
104 return;
105 case TypeCode.Boolean:
106 ConstantWrapper.TranslateToILInt(il, ic.ToInt32(null));
107 Convert.Emit(this, il, Typeob.Boolean, rtype);
108 return;
109 case TypeCode.Char:
110 case TypeCode.SByte:
111 case TypeCode.Byte:
112 case TypeCode.Int16:
113 case TypeCode.UInt16:
114 case TypeCode.Int32:
115 ConstantWrapper.TranslateToILInt(il, ic.ToInt32(null));
116 if (rtype.IsEnum) return;
117 if (val is EnumWrapper)
118 Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
119 else
120 Convert.Emit(this, il, Globals.TypeRefs.ToReferenceContext(val.GetType()), rtype);
121 return;
122 case TypeCode.UInt32:
123 ConstantWrapper.TranslateToILInt(il, (int)ic.ToUInt32(null));
124 if (rtype.IsEnum) return;
125 if (val is EnumWrapper)
126 Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
127 else
128 Convert.Emit(this, il, Typeob.UInt32, rtype);
129 return;
130 case TypeCode.Int64:
131 long l = ic.ToInt64(null);
132 if (Int32.MinValue <= l && l <= Int32.MaxValue){
133 ConstantWrapper.TranslateToILInt(il, (int)l);
134 il.Emit(OpCodes.Conv_I8);
135 }else
136 il.Emit(OpCodes.Ldc_I8, l);
137 if (rtype.IsEnum) return;
138 if (val is EnumWrapper)
139 Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
140 else
141 Convert.Emit(this, il, Typeob.Int64, rtype);
142 return;
143 case TypeCode.UInt64:
144 ulong ul = ic.ToUInt64(null);
145 if (ul <= Int32.MaxValue){
146 ConstantWrapper.TranslateToILInt(il, (int)ul);
147 il.Emit(OpCodes.Conv_I8);
148 }else
149 il.Emit(OpCodes.Ldc_I8, (long)ul);
150 if (rtype.IsEnum) return;
151 if (val is EnumWrapper)
152 Convert.Emit(this, il, ((EnumWrapper)val).type, rtype);
153 else
154 Convert.Emit(this, il, Typeob.UInt64, rtype);
155 return;
156 case TypeCode.Single:
157 float f = ic.ToSingle(null);
158 if (f == f && (f != 0 || !Single.IsNegativeInfinity(1 / f))){
159 int i = (int)Runtime.DoubleToInt64(f);
160 if (-128 <= i && i <= 127 && f == (float)i){
161 ConstantWrapper.TranslateToILInt(il, i);
162 il.Emit(OpCodes.Conv_R4);
163 }else
164 il.Emit(OpCodes.Ldc_R4, f);
165 }else
166 il.Emit(OpCodes.Ldc_R4, f);
167 Convert.Emit(this, il, Typeob.Single, rtype);
168 return;
169 case TypeCode.Double:
170 double d = ic.ToDouble(null);
171 if (d == d && (d != 0 || !Double.IsNegativeInfinity(1 / d))){
172 int i = (int)Runtime.DoubleToInt64(d);
173 if (-128 <= i && i <= 127 && d == (double)i){
174 ConstantWrapper.TranslateToILInt(il, i);
175 il.Emit(OpCodes.Conv_R8);
176 }else
177 il.Emit(OpCodes.Ldc_R8, d);
178 }else
179 il.Emit(OpCodes.Ldc_R8, d);
180 Convert.Emit(this, il, Typeob.Double, rtype);
181 return;
182 case TypeCode.Decimal:
183 int[] bits = Decimal.GetBits(ic.ToDecimal(null));
184 ConstantWrapper.TranslateToILInt(il, bits[0]);
185 ConstantWrapper.TranslateToILInt(il, bits[1]);
186 ConstantWrapper.TranslateToILInt(il, bits[2]);
187 il.Emit(bits[3] < 0 ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0); //bool isNegative
188 ConstantWrapper.TranslateToILInt(il, (bits[3]&0x7FFFFFFF)>>16);
189 il.Emit(OpCodes.Newobj, CompilerGlobals.decimalConstructor);
190 Convert.Emit(this, il, Typeob.Decimal, rtype);
191 return;
192 case TypeCode.DateTime:
193 l = ic.ToDateTime(null).Ticks;
194 il.Emit(OpCodes.Ldc_I8, l);
195 Convert.Emit(this, il, Typeob.Int64, rtype);
196 return;
197 case TypeCode.String:
198 String str = ic.ToString(null);
199 if (rtype == Typeob.Char && str.Length == 1){
200 ConstantWrapper.TranslateToILInt(il, (int)str[0]);
201 return;
203 il.Emit(OpCodes.Ldstr, str);
204 Convert.Emit(this, il, Typeob.String, rtype);
205 return;
207 if (val is Enum){
208 if (rtype == Typeob.String)
209 this.TranslateToIL(il, val.ToString(), rtype);
210 else if (rtype.IsPrimitive)
211 this.TranslateToIL(il, System.Convert.ChangeType(val, Enum.GetUnderlyingType(Globals.TypeRefs.ToReferenceContext(val.GetType())), CultureInfo.InvariantCulture), rtype);
212 else{
213 Type et = Globals.TypeRefs.ToReferenceContext(val.GetType());
214 Type ut = Enum.GetUnderlyingType(et);
215 this.TranslateToIL(il, System.Convert.ChangeType(val, ut, CultureInfo.InvariantCulture), ut);
216 il.Emit(OpCodes.Box, et);
217 Convert.Emit(this, il, Typeob.Object, rtype);
219 return;
221 if (val is EnumWrapper){
222 if (rtype == Typeob.String)
223 this.TranslateToIL(il, val.ToString(), rtype);
224 else if (rtype.IsPrimitive)
225 this.TranslateToIL(il, ((EnumWrapper)val).ToNumericValue(), rtype);
226 else{
227 Type et = ((EnumWrapper)val).type;
228 Type ut = Globals.TypeRefs.ToReferenceContext(((EnumWrapper)val).value.GetType());
229 this.TranslateToIL(il, ((EnumWrapper)val).value, ut);
230 il.Emit(OpCodes.Box, et);
231 Convert.Emit(this, il, Typeob.Object, rtype);
233 return;
235 if (val is Type){
236 il.Emit(OpCodes.Ldtoken, (Type)val);
237 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
238 Convert.Emit(this, il, Typeob.Type, rtype);
239 }else if (val is Namespace){
240 il.Emit(OpCodes.Ldstr, ((Namespace)val).Name);
241 this.EmitILToLoadEngine(il);
242 il.Emit(OpCodes.Call, CompilerGlobals.getNamespaceMethod);
243 Convert.Emit(this, il, Typeob.Namespace, rtype);
244 }else if (val is ClassScope){
245 il.Emit(OpCodes.Ldtoken, ((ClassScope)val).GetTypeBuilderOrEnumBuilder());
246 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
247 Convert.Emit(this, il, Typeob.Type, rtype);
248 }else if (val is TypedArray){
249 il.Emit(OpCodes.Ldtoken, Convert.ToType((TypedArray)val));
250 il.Emit(OpCodes.Call, CompilerGlobals.getTypeFromHandleMethod);
251 Convert.Emit(this, il, Typeob.Type, rtype);
252 }else if (val is NumberObject){
253 this.TranslateToIL(il, ((NumberObject)val).value, Typeob.Object);
254 this.EmitILToLoadEngine(il);
255 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
256 Convert.Emit(this, il, Typeob.NumberObject, rtype);
257 }else if (val is StringObject){
258 il.Emit(OpCodes.Ldstr, ((StringObject)val).value);
259 this.EmitILToLoadEngine(il);
260 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
261 Convert.Emit(this, il, Typeob.StringObject, rtype);
262 }else if (val is BooleanObject){
263 il.Emit(((BooleanObject)val).value ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0);
264 il.Emit(OpCodes.Box, Typeob.Boolean);
265 this.EmitILToLoadEngine(il);
266 il.Emit(OpCodes.Call, CompilerGlobals.toObjectMethod);
267 Convert.Emit(this, il, Typeob.BooleanObject, rtype);
268 }else if (val is ActiveXObjectConstructor){
269 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("ActiveXObject").GetGetMethod());
270 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
271 }else if (val is ArrayConstructor){
272 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Array").GetGetMethod());
273 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
274 }else if (val is BooleanConstructor){
275 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Boolean").GetGetMethod());
276 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
277 }else if (val is DateConstructor){
278 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Date").GetGetMethod());
279 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
280 }else if (val is EnumeratorConstructor){
281 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Enumerator").GetGetMethod());
282 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
283 }else if (val is ErrorConstructor){
284 ErrorConstructor error = (ErrorConstructor)val;
285 if (error == ErrorConstructor.evalOb)
286 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("EvalError").GetGetMethod());
287 else if (error == ErrorConstructor.rangeOb)
288 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("RangeError").GetGetMethod());
289 else if (error == ErrorConstructor.referenceOb)
290 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("ReferenceError").GetGetMethod());
291 else if (error == ErrorConstructor.syntaxOb)
292 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("SyntaxError").GetGetMethod());
293 else if (error == ErrorConstructor.typeOb)
294 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("TypeError").GetGetMethod());
295 else if (error == ErrorConstructor.uriOb)
296 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("URIError").GetGetMethod());
297 else
298 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Error").GetGetMethod());
299 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
300 }else if (val is FunctionConstructor){
301 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Function").GetGetMethod());
302 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
303 }else if (val is MathObject){
304 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Math").GetGetMethod());
305 Convert.Emit(this, il, Typeob.JSObject, rtype);
306 }else if (val is NumberConstructor){
307 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Number").GetGetMethod());
308 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
309 }else if (val is ObjectConstructor){
310 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("Object").GetGetMethod());
311 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
312 }else if (val is RegExpConstructor){
313 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("RegExp").GetGetMethod());
314 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
315 }else if (val is StringConstructor){
316 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("String").GetGetMethod());
317 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
318 }else if (val is VBArrayConstructor){
319 il.Emit(OpCodes.Call, Typeob.GlobalObject.GetProperty("VBArray").GetGetMethod());
320 Convert.Emit(this, il, Typeob.ScriptFunction, rtype);
321 }else if (val is IntPtr){
322 il.Emit(OpCodes.Ldc_I8, (long)(IntPtr)val);
323 il.Emit(OpCodes.Conv_I);
324 Convert.Emit(this, il, Typeob.IntPtr, rtype);
325 }else if (val is UIntPtr){
326 il.Emit(OpCodes.Ldc_I8, (long)(UIntPtr)val);
327 il.Emit(OpCodes.Conv_U);
328 Convert.Emit(this, il, Typeob.UIntPtr, rtype);
329 }else if (val is Missing){
330 il.Emit(OpCodes.Ldsfld, CompilerGlobals.missingField);
331 Convert.Emit(this, il, Typeob.Object, rtype);
332 }else if (val is System.Reflection.Missing){
333 if (rtype.IsPrimitive)
334 this.TranslateToIL(il, Double.NaN, rtype);
335 else if (rtype != Typeob.Object && !rtype.IsValueType)
336 il.Emit(OpCodes.Ldnull);
337 else{
338 il.Emit(OpCodes.Ldsfld, CompilerGlobals.systemReflectionMissingField);
339 Convert.Emit(this, il, Typeob.Object, rtype);
341 }else if (val != this.value) //Value was coerced to some type we have no compile time knowlegde of
342 this.TranslateToIL(il, this.value, rtype);
343 else
344 throw new JScriptException(JSError.InternalError, this.context); //It should not be possible to wrap any other kind of object
347 internal static void TranslateToILInt(ILGenerator il, int i){
348 switch (i){
349 case -1:il.Emit(OpCodes.Ldc_I4_M1); break;
350 case 0: il.Emit(OpCodes.Ldc_I4_0); break;
351 case 1: il.Emit(OpCodes.Ldc_I4_1); break;
352 case 2: il.Emit(OpCodes.Ldc_I4_2); break;
353 case 3: il.Emit(OpCodes.Ldc_I4_3); break;
354 case 4: il.Emit(OpCodes.Ldc_I4_4); break;
355 case 5: il.Emit(OpCodes.Ldc_I4_5); break;
356 case 6: il.Emit(OpCodes.Ldc_I4_6); break;
357 case 7: il.Emit(OpCodes.Ldc_I4_7); break;
358 case 8: il.Emit(OpCodes.Ldc_I4_8); break;
359 default:
360 if (-128 <= i && i <= 127)
361 il.Emit(OpCodes.Ldc_I4_S, (SByte)i);
362 else
363 il.Emit(OpCodes.Ldc_I4, i);
364 break;
368 internal override void TranslateToILInitializer(ILGenerator il){